﻿using System;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using O1.Kernel;
using O1.Kernel.Primitives;

namespace Tests.O1.Kernel.Primitives
{
    [TestClass]
    public class CellAddressTests
    {
        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressWriteLocalIdWritesExpectedValue()
        {
            uint expected = 123456;
            var buffer = new byte[Sz.CLR.Int32];
            CellAddress.WriteLocalId(expected, buffer, 0);
            var actual = BitConverter.ToUInt32(buffer, 0);

            actual.Should().Be(expected);
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressReadLocalIdReturnsExpectedValue()
        {
            uint value = 123456;
            var buffer = BitConverter.GetBytes(value);
            var subject = CellAddress.ReadLocalId(22, buffer, 0);
            subject.CellId.Should().Be(value);
            subject.TrunkId.Should().Be(22);
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressWritesDataIntoPackedSizeBufferAsExpected()
        {
            var subject = new CellAddress(6, 122);
            var buffer = new byte[CellAddress.Size];
            subject.Write(buffer, 0);
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressWritesDataValuesAsExpected()
        {
            var subject = new CellAddress(99, 12200);
            var buffer = new byte[CellAddress.Size];
            subject.Write(buffer, 0);

            var actualValue = BitConverter.ToInt32(buffer, 0);
            var actualKey = BitConverter.ToInt16(buffer, 4);

            actualValue.Should().Be(12200);
            actualKey.Should().Be(99);
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressReadsAsExpected()
        {
            var buffer = new byte[CellAddress.Size];
            var data = BitConverter.GetBytes(678000999);
            var key = BitConverter.GetBytes((short)77);

            Array.Copy(data, buffer, 4);
            Array.Copy(key, 0, buffer, 4, 2);

            var subject = CellAddress.Read(buffer, 0);
            subject.TrunkId.Should().Be(77);
            subject.CellId.Should().Be(678000999);
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressWritesThenReadsAsExpected()
        {
            var expected = new CellAddress(99, 12200);
            var buffer = new byte[CellAddress.Size];
            expected.Write(buffer, 0);

            var actual = CellAddress.Read(buffer, 0);
            actual.TrunkId.Should().Be(expected.TrunkId);
            actual.CellId.Should().Be(expected.CellId);
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressEqualityIsKeyValueEquality()
        {
            var subject1 = new CellAddress(99, 12200);
            var subject2 = new CellAddress(99, 12200);
            (subject1 == subject2).Should().BeTrue();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressInequalityIsKeyInequality()
        {
            var subject1 = new CellAddress(99, 12200);
            var subject2 = new CellAddress(98, 12200);
            (subject1 != subject2).Should().BeTrue();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressInequalityIsValueInequality()
        {
            var subject1 = new CellAddress(98, 124500);
            var subject2 = new CellAddress(98, 12200);
            (subject1 != subject2).Should().BeTrue();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressEqualsIsValueEquality()
        {
            var subject1 = new CellAddress(99, 12200);
            var subject2 = new CellAddress(99, 12200);
            subject1.Equals(subject2).Should().BeTrue();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressEqualsIsKeyInequality()
        {
            var subject1 = new CellAddress(99, 12200);
            var subject2 = new CellAddress(98, 12200);
            subject1.Equals(subject2).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressEqualsIsValueInequality()
        {
            var subject1 = new CellAddress(98, 124500);
            var subject2 = new CellAddress(98, 12200);
            subject1.Equals(subject2).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressIsNotEqualToNull()
        {
            object other = null;
            new CellAddress(98, 124500).Equals(other).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressGetHashCodeIsConsistent()
        {
            var subject = new CellAddress(98, 124500);
            subject.GetHashCode().Should().Be(subject.GetHashCode());   
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressGetHashCodeIsDifferentForDifferentKey()
        {
            var subject1 = new CellAddress(98, 124500);
            var subject2 = new CellAddress(101, 124500);
            subject1.GetHashCode().Should().NotBe(subject2.GetHashCode());
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressGetHashCodeIsDifferentForDifferentValue()
        {
            var subject1 = new CellAddress(101, 124500);
            var subject2 = new CellAddress(101, 1200);
            subject1.GetHashCode().Should().NotBe(subject2.GetHashCode());
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressGetHashCodeIsDifferentForDifferentKeyAndValue()
        {
            var subject1 = new CellAddress(88, 124500);
            var subject2 = new CellAddress(101, 1200);
            subject1.GetHashCode().Should().NotBe(subject2.GetHashCode());
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressObjectEqualsIsEquality()
        {
            var subject1 = new CellAddress(98, 124500);
            object subject2 = new CellAddress(98, 124500);
            subject1.Equals(subject2).Should().BeTrue();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressObjectEqualsIsInequalityForDifferentKey()
        {
            var subject1 = new CellAddress(99, 124500);
            object subject2 = new CellAddress(98, 124500);
            subject1.Equals(subject2).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressObjectEqualsIsInequalityForDifferentValue()
        {
            var subject1 = new CellAddress(99, 124500);
            object subject2 = new CellAddress(99, 500);
            subject1.Equals(subject2).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressObjectEqualsIsInequalityForDifferentKeyAndValue()
        {
            var subject1 = new CellAddress(8769, 124500);
            object subject2 = new CellAddress(99, 500);
            subject1.Equals(subject2).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void CellAddressObjectEqualsIsInequalityForDifferentType()
        {
            var subject1 = new CellAddress(99, 124500);
            object subject2 = new object();
            subject1.Equals(subject2).Should().BeFalse();
        }
    }
}
